﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DetectiveCluedo.Components;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;

namespace DetectiveCluedo
{
    // A delegate type for hooking up change notifications.
    public delegate void ChangedEventHandler();

    public static class CluedoGame
    {

        // An event that clients can use to be notified whenever the
        // elements of the list change.
        public static event ChangedEventHandler Changed;


        public static Player[] Players { get; set; }

        //private static List<PlayerCardInfo> _playerCardInfoList;
        private static ObservableList<PlayerCardInfo> _playerCardInfoList;
        private static ObservableList<GameLog> _gameLogList;

        private static bool _playerCardInfoChanged;
        public static bool PlayerCardInfoChanged
        {
            get { return _playerCardInfoChanged; }
            set
            {
                _playerCardInfoChanged = value;
            }
        }


        #region Solution
        private static Card _suspectCardSolution;
        public static Card SuspectCardSolution
        {
            get { return _suspectCardSolution; }
        }

        private static Card _weaponCardSolution;
        public static Card WeaponCardSolution
        {
            get { return _weaponCardSolution; }
        }

        private static Card _roomCardSolution;
        public static Card RoomCardSolution
        {
            get { return _roomCardSolution; }
        }
        #endregion Solution


        public static int SuspectsLeftCount
        {
            get
            {
                if (SuspectCardSolution != null)
                    return 0;
                else
                    return _playerCardInfoList.Where(p => p.Card.Type == ECardType.Suspect).Count() / Players.Length
                    - _playerCardInfoList.Where(p => p.Card.Type == ECardType.Suspect && p.PlayerHasCard == true).Count();
            }
        }

        public static int WeaponsLeftCount
        {
            get
            {

                if (WeaponCardSolution != null)
                    return 0;
                else
                    return _playerCardInfoList.Where(p => p.Card.Type == ECardType.Weapon).Count() / Players.Length
                    - _playerCardInfoList.Where(p => p.Card.Type == ECardType.Weapon && p.PlayerHasCard == true).Count();
            }
        }

        public static int RoomsLeftCount
        {
            get
            {
                if (RoomCardSolution != null)
                    return 0;
                else
                    return _playerCardInfoList.Where(p => p.Card.Type == ECardType.Room).Count() / CluedoGame.Players.Length
                    - _playerCardInfoList.Where(p => p.Card.Type == ECardType.Room && p.PlayerHasCard == true).Count();
            }
        }

        public static double TableCompleteness
        {
            get
            {
                return 1.0 * _playerCardInfoList.Where(p => p.PlayerHasCard.HasValue).Count() / _playerCardInfoList.Count();
            }
        }

        public static int ErrorCount { get { return _playerCardInfoList.Where(p => !string.IsNullOrEmpty(p.ErrorText)).Count(); } }

        static CluedoGame()
        {
            _gameLogList = new ObservableList<GameLog>();
            _gameLogList.Changed += new Components.ChangedEventHandler(_gameLogList_Changed);

            _playerCardInfoList = new ObservableList<PlayerCardInfo>();
            _playerCardInfoList.Changed += new Components.ChangedEventHandler(_playerCardInfoList_Changed);


        }

        static void _gameLogList_Changed(object sender, EventArgs e)
        {
            Investigate();
            OnChanged();
            //Console.WriteLine("List changed at {0}", DateTime.Now);
        }

        static void _playerCardInfoList_Changed(object sender, EventArgs e)
        {
            OnChanged();
            //Console.WriteLine("List changed at {0}", DateTime.Now);
        }



        public static void StartNewGame()
        {
            Players = null;

            _playerCardInfoList.Changed -= new Components.ChangedEventHandler(_playerCardInfoList_Changed);
            _playerCardInfoList.Clear();
            _playerCardInfoList.Changed += new Components.ChangedEventHandler(_playerCardInfoList_Changed);

            _gameLogList.Changed -= new Components.ChangedEventHandler(_gameLogList_Changed);
            _gameLogList.Clear();
            _gameLogList.Changed += new Components.ChangedEventHandler(_gameLogList_Changed);
        }

        // Invoke the Changed event; called whenever list changes
        public static void OnChanged()
        {
            if (Changed != null)
                Changed();
        }

        public static Card[] Cards
        {
            get
            {
                List<Card> cards = new List<Card>();

                string[] suspects = Properties.Settings.Default.Suspects.Split(',');
                string[] weapons = Properties.Settings.Default.Weapons.Split(',');
                string[] rooms = Properties.Settings.Default.Rooms.Split(',');

                foreach (string suspect in suspects)
                {
                    string name;
                    int argb;
                    if (suspect.IndexOf("[") != -1)
                    {
                        name = GetNameFromSuspectString(suspect);
                        string s = suspect.Substring(suspect.IndexOf("[") + 1, suspect.IndexOf("]") - suspect.IndexOf("[") - 1);
                        argb = Convert.ToInt32(s);
                        if (argb != 0)
                            cards.Add(new Card() { Name = name, Type = ECardType.Suspect, Color = Color.FromArgb(argb) });
                        else
                            cards.Add(new Card() { Name = name, Type = ECardType.Suspect });
                    }
                    else
                        cards.Add(new Card() { Name = suspect, Type = ECardType.Suspect });
                }
                foreach (string weapon in weapons)
                {
                    cards.Add(new Card() { Name = weapon, Type = ECardType.Weapon });
                }
                foreach (string room in rooms)
                {
                    cards.Add(new Card() { Name = room, Type = ECardType.Room });
                }

                return cards.ToArray();
            }
        }

        public static string GetNameFromSuspectString(string suspect)
        {
            if (suspect.IndexOf("[") != -1)
                return suspect.Substring(0, suspect.IndexOf("["));
            return suspect;
        }

        public static bool DoesSomeoneHasCard(Card card)
        {
            return _playerCardInfoList.Where(p => p.Card.Equals(card) && p.PlayerHasCard == true).Count() > 0;
        }

        /*
        public static Color GetPlayerColor(string suspect)
        {
            string[] suspects = Properties.Settings.Default.Suspects.Split(',');
            foreach (string s in suspects)
            {
                string name = GetNameFromSuspectString(s);
                if (name == suspect)
                {
                    string col = s.Substring(s.IndexOf("[") + 1, s.IndexOf("]") - s.IndexOf("[") - 1);
                    int iCol = Convert.ToInt32(col);
                    if(iCol != 0)
                        return Color.FromArgb(iCol);
                    return Color.White;
                }
            }
            return Color.White;
        }
         * */

        public static int TotalCardsCount
        {
            get { return Cards.Length; }
        }


        public static void CreatePlayers(string[] playersNames)
        {
            List<Player> players = new List<Player>();
            int cardsToDistribute = TotalCardsCount - 3;

            for (int i = 0; i < playersNames.Length; i++)
            {
                players.Add(new Player() { Name = playersNames[i], CardsCount = Convert.ToInt32(Math.Ceiling(1.0 * (cardsToDistribute - i) / playersNames.Length)) });
            }
            Players = players.ToArray();
        }

        public static bool SetYourself(string you)
        {
            Player p = GetPlayerByName(you);

            if (p != null)
            {
                p.IsYou = true;
            }

            return p != null && p.IsYou;
        }

        public static Player GetYourself()
        {
            return Players.Where(p => p.IsYou).SingleOrDefault();
        }

        public static Player GetPlayerByName(string name)
        {
            foreach (Player p in Players)
            {
                if (p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                {
                    return p;
                }
            }

            return null;
        }

        public static Player GetNextPlayer(Player player)
        {
            int indexOfInputPlayer = -1;
            for (int i = 0; i < Players.Length; i++)
            {
                if (Players[i].Equals(player))
                {
                    indexOfInputPlayer = i;
                    break;
                }
            }

            if (indexOfInputPlayer != -1)
                return Players[(indexOfInputPlayer + 1) % Players.Length];

            return null;
        }

        public static Card GetCardByNameAndType(string name, ECardType type)
        {
            foreach (Card c in Cards)
            {
                if (c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) && c.Type == type)
                {
                    return c;
                }
            }

            return null;
        }


        public static PlayerCardInfo SetPlayersCardInfo(Player player, Card card, bool? stat, EPlayerCardInfoStatusReason reason, int suggestion = -1)
        {
            PlayerCardInfo playersCardInfo = _playerCardInfoList.Find(pci => pci.Player.Equals(player) && pci.Card.Equals(card));

            if (playersCardInfo != null)
            {
                if (playersCardInfo.Suggestion != -1 && suggestion == -1)
                    suggestion = playersCardInfo.Suggestion;

                if (playersCardInfo.PlayerHasCard != stat || playersCardInfo.Reason != reason || playersCardInfo.Suggestion != suggestion)
                {
                    PlayerCardInfoChanged = true;

                    playersCardInfo.PlayerHasCard = stat;
                    playersCardInfo.Reason = reason;
                    playersCardInfo.Suggestion = suggestion;
                }
                return playersCardInfo;
            }
            else
            {
                PlayerCardInfoChanged = true;

                var pki = new PlayerCardInfo() { Player = player, Card = card, PlayerHasCard = stat, Reason = reason, Suggestion = suggestion };
                _playerCardInfoList.Add(pki);
                return pki;
            }
        }

        public static PlayerCardInfo GetPlayersCardInfo(Player player, Card card)
        {
            return _playerCardInfoList.Find(pci => pci.Player.Equals(player) && pci.Card.Equals(card));
        }


        public static bool Investigate()
        {
            Player nextPlayer, currentPlayer;

            try
            {

                // Clear all i.e. set all player/card info to unknown
                foreach (Player p in Players)
                {
                    foreach (Card c in Cards)
                    {
                        if (GetPlayersCardInfo(p, c) == null)
                            SetPlayersCardInfo(p, c, null, EPlayerCardInfoStatusReason.Unknown);
                    }
                }

                // Set all player/card info to unknown, except my/you cards
                foreach (PlayerCardInfo pki in _playerCardInfoList.Where(p => p.Reason != EPlayerCardInfoStatusReason.MyCard))
                {
                    //pki.Status = EPlayersCardInfoStatus.Unknown;
                    pki.PlayerHasCard = null;
                    pki.Reason = EPlayerCardInfoStatusReason.Unknown;
                }

                investigateAll();

                foreach (GameLog gameLog in _gameLogList)
                {
                    //currentPlayer = GetYourself();
                    currentPlayer = gameLog.MovePlayer;

                    if (gameLog.DisapprovePlayer == null)
                    {
                        foreach (Player player in Players.Where(p => !p.Equals(gameLog.MovePlayer)))
                        {
                            SetPlayersCardInfo(player, gameLog.SuspectCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                            SetPlayersCardInfo(player, gameLog.WeaponCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                            SetPlayersCardInfo(player, gameLog.RoomCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                        }
                    }
                    else
                    {
                        do
                        {
                            nextPlayer = GetNextPlayer(currentPlayer);

                            // If next player doesn't have any of the cards
                            if (!nextPlayer.Equals(gameLog.DisapprovePlayer))
                            {
                                SetPlayersCardInfo(nextPlayer, gameLog.SuspectCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                                SetPlayersCardInfo(nextPlayer, gameLog.WeaponCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                                SetPlayersCardInfo(nextPlayer, gameLog.RoomCard, false, EPlayerCardInfoStatusReason.DoesNotHaveThatCard);
                            }

                            investigateAll();

                            currentPlayer = nextPlayer;

                            if (gameLog.DisapprovePlayer == null)
                            {
                                int i = 9;
                            }
                        }
                        while (!nextPlayer.Equals(gameLog.DisapprovePlayer)/* && !nextPlayer.Equals(nextPlayer)*/);


                        if (nextPlayer.Equals(gameLog.DisapprovePlayer))
                        {
                            if (gameLog.MovePlayer.Equals(GetYourself()))
                            {
                                SetPlayersCardInfo(nextPlayer, gameLog.ShownCard, true, EPlayerCardInfoStatusReason.CardShownByOtherPlayer);
                            }
                            else
                            {

                            }
                        }
                    }
                    investigateAll();
                }

                investigateAll();
            }
            catch { }

            return _suspectCardSolution != null && _weaponCardSolution != null && _roomCardSolution != null;
        }

        public static PlayerCardInfo[] GetPlayerCardInfoLog()
        {
            return _playerCardInfoList.ToArray();
        }

        public static void AddGameLog(GameLog gameLog)
        {
            _gameLogList.Add(gameLog);
        }

        public static void UpdateGameLog(GameLog gameLog, int index)
        {
            _gameLogList[index] = gameLog;
        }

        public static void DeleteGameLog(int index)
        {
            _gameLogList.RemoveAt(index);
        }

        private static void investigateAll()
        {
            int maxLoops = 10000;
            int k = 0;

            do
            {
                PlayerCardInfoChanged = false;

                investigateIfSomeoneElseHasCard();
                investigateIfPlayerCannotHaveMoreCards();
                //inspectCardsThatNooneElseHas();
                investigateSuggestions();
                //inspectIfNoneDoesNotHaveSomeCard();
                searchForTheSolution();

                checkForPlayerCardInfoErrors();
            }
            while (PlayerCardInfoChanged && ++k < maxLoops);


            if (k == maxLoops)
            {
                PlayerCardInfoChanged = false;
                MessageBox.Show("Please check code! There is high number of investigation loops detected {0}.", k.ToString());
            }
        }

        private static void checkForPlayerCardInfoErrors()
        {
            foreach (PlayerCardInfo pci in _playerCardInfoList)
            {
                pci.ErrorText = string.Empty;
            }


            // check if some player has more cards than possible
            foreach (Player player in Players)
            {
                int cc = _playerCardInfoList.Where(p => p.Player.Equals(player) && p.PlayerHasCard == true).Count();
                if (cc > player.CardsCount)
                {
                    foreach (PlayerCardInfo pci in _playerCardInfoList.Where(p => p.Player.Equals(player) && p.PlayerHasCard == true))
                    {
                        pci.ErrorText = string.Format("Player {0} should have {1} cards but it has {2} cards", player.Name, player.CardsCount, cc);
                    }
                }
            }

            // check if some card is "taken" twice
            foreach (Card card in Cards)
            {
                if (_playerCardInfoList.Where(c => c.Card.Equals(card) && c.PlayerHasCard == true).ToArray().Length > 1)
                {
                    foreach (PlayerCardInfo pci in _playerCardInfoList.Where(c => c.Card.Equals(card) && c.PlayerHasCard == true))
                    {
                        pci.ErrorText = string.Format("More than one player has {0} card", card.Name);
                    }
                }
            }
        }

        private static void searchForTheSolution()
        {
            try
            {
                if (SuspectsLeftCount == 1)
                {
                    _suspectCardSolution = GetCardByNameAndType(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Suspect).Select(c => c.Card.Name).Distinct().Except(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Suspect && p.PlayerHasCard == true).Select(c => c.Card.Name).Distinct()).SingleOrDefault(), ECardType.Suspect);
                    PlayerCardInfoChanged = true;
                }

                if (WeaponsLeftCount == 1)
                {
                    _weaponCardSolution = GetCardByNameAndType(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Weapon).Select(c => c.Card.Name).Distinct().Except(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Weapon && p.PlayerHasCard == true).Select(c => c.Card.Name).Distinct()).SingleOrDefault(), ECardType.Weapon);
                    PlayerCardInfoChanged = true;
                }

                if (RoomsLeftCount == 1)
                {
                    _roomCardSolution = GetCardByNameAndType(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Room).Select(c => c.Card.Name).Distinct().Except(
                        _playerCardInfoList.Where(p => p.Card.Type == ECardType.Room && p.PlayerHasCard == true).Select(c => c.Card.Name).Distinct()).SingleOrDefault(), ECardType.Room);
                    PlayerCardInfoChanged = true;
                }


                if (_suspectCardSolution != null)
                {
                    foreach (PlayerCardInfo pki in _playerCardInfoList.Where(p => p.Card.Equals(_suspectCardSolution) && !p.PlayerHasCard.HasValue /*!= EPlayersCardInfoStatus.Yes && p.Status != EPlayersCardInfoStatus.No*/))
                    {
                        //pki.Status = EPlayersCardInfoStatus.No;
                        pki.PlayerHasCard = false;
                        pki.Reason = EPlayerCardInfoStatusReason.Solution;
                        PlayerCardInfoChanged = true;
                    }
                }

                if (_weaponCardSolution != null)
                {
                    foreach (PlayerCardInfo pki in _playerCardInfoList.Where(p => p.Card.Equals(_weaponCardSolution) && !p.PlayerHasCard.HasValue /*Status != EPlayersCardInfoStatus.Yes && p.Status != EPlayersCardInfoStatus.No*/))
                    {
                        //pki.Status = EPlayersCardInfoStatus.No;
                        pki.PlayerHasCard = false;
                        pki.Reason = EPlayerCardInfoStatusReason.Solution;
                        PlayerCardInfoChanged = true;
                    }
                }

                if (_roomCardSolution != null)
                {
                    foreach (PlayerCardInfo pki in _playerCardInfoList.Where(p => p.Card.Equals(_roomCardSolution) && !p.PlayerHasCard.HasValue /*.Status != EPlayersCardInfoStatus.Yes && p.Status != EPlayersCardInfoStatus.No*/))
                    {
                        //pki.Status = EPlayersCardInfoStatus.No;
                        pki.PlayerHasCard = false;
                        pki.Reason = EPlayerCardInfoStatusReason.Solution;
                        PlayerCardInfoChanged = true;
                    }
                }

                foreach (Card card in Cards.Where(c => !c.Equals(_suspectCardSolution) && !c.Equals(_weaponCardSolution) && !c.Equals(_roomCardSolution)))
                {
                    if (_playerCardInfoList.Where(p => p.Card.Equals(card) && p.PlayerHasCard == false /* p.Status == EPlayersCardInfoStatus.No*/).Count() == Players.Length)
                    {
                        switch (card.Type)
                        {
                            case ECardType.Suspect: _suspectCardSolution = card; break;
                            case ECardType.Weapon: _weaponCardSolution = card; break;
                            case ECardType.Room: _roomCardSolution = card; break;
                        };
                        PlayerCardInfoChanged = true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// For every card, method checks if someone has it and sets No for all other players if someone does.
        /// </summary>
        private static void investigateIfSomeoneElseHasCard()
        {
            try
            {
                var foundCards = _playerCardInfoList.Where(p => p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).ToList();

                foreach (PlayerCardInfo pci in foundCards)
                {
                    foreach (Player player in Players)
                    {
                        var pci2 = GetPlayersCardInfo(player, pci.Card);
                        if (pci2 == null || pci2 != null && !pci2.PlayerHasCard.HasValue /*pci2.Status != EPlayersCardInfoStatus.Yes && pci2.Status != EPlayersCardInfoStatus.No*/)
                        {
                            SetPlayersCardInfo(player, pci.Card, /*EPlayersCardInfoStatus.No*/ false, EPlayerCardInfoStatusReason.SomeoneElseHasThatCard);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// For every player, system checks if all his cards are "found" and sets NO for all remaining cards
        /// </summary>
        private static void investigateIfPlayerCannotHaveMoreCards()
        {
            try
            {
                foreach (Player player in Players)
                {
                    if (_playerCardInfoList.Where(p => p.Player.Equals(player) && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).ToList().Count == player.CardsCount)
                    {
                        foreach (Card card in CluedoGame.Cards)
                        {
                            var pci2 = GetPlayersCardInfo(player, card);
                            if (pci2 == null || pci2 != null && !pci2.PlayerHasCard.HasValue /*pci2.Status != EPlayersCardInfoStatus.Yes && pci2.Status != EPlayersCardInfoStatus.No*/)
                            {
                                SetPlayersCardInfo(player, card, /*EPlayersCardInfoStatus.No*/ false, EPlayerCardInfoStatusReason.CannotHaveMoreCards);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        /// <summary>
        /// For every log, set NO to all fields that noone has and make an assumptions...
        /// </summary>
        private static void investigateSuggestions()
        {
            try
            {
                //for (int i = 0; i < _otherPlayersSuggestionList.Count; i++)
                for (int i = 0; i < _gameLogList.Count; i++)
                {
                    Suggestion sugg = new Suggestion()
                    {
                        MovePlayer = _gameLogList[i].MovePlayer,
                        ConfirmPlayer = _gameLogList[i].DisapprovePlayer,
                        SuspectCard = _gameLogList[i].SuspectCard,
                        WeaponCard = _gameLogList[i].WeaponCard,
                        RoomCard = _gameLogList[i].RoomCard
                    };

                    if (sugg.ConfirmPlayer == null)
                    {
                        var pki1 = GetPlayersCardInfo(sugg.MovePlayer, sugg.SuspectCard);
                        var pki2 = GetPlayersCardInfo(sugg.MovePlayer, sugg.WeaponCard);
                        var pki3 = GetPlayersCardInfo(sugg.MovePlayer, sugg.RoomCard);

                        if (pki1.PlayerHasCard == false/*pki1.Status == EPlayersCardInfoStatus.No*/ && _playerCardInfoList.Where(p => p.Card.Equals(sugg.SuspectCard) && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).Count() == 0)
                            _suspectCardSolution = sugg.SuspectCard;
                        if (pki2.PlayerHasCard == false/*pki2.Status == EPlayersCardInfoStatus.No*/ && _playerCardInfoList.Where(p => p.Card.Equals(sugg.WeaponCard) && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).Count() == 0)
                            _weaponCardSolution = sugg.WeaponCard;
                        if (pki3.PlayerHasCard == false/*pki3.Status == EPlayersCardInfoStatus.No*/ && _playerCardInfoList.Where(p => p.Card.Equals(sugg.RoomCard) && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).Count() == 0)
                            _roomCardSolution = sugg.RoomCard;
                    }
                    else
                    {

                        if (!sugg.ConfirmPlayer.Equals(GetYourself()) && !sugg.MovePlayer.Equals(GetYourself()))
                        {
                            // check if player has some of the suggested cards

                            if (_playerCardInfoList.Where(p => p.Card.Equals(sugg.SuspectCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).Union(
                                _playerCardInfoList.Where(p => p.Card.Equals(sugg.WeaponCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/)).Union(
                                _playerCardInfoList.Where(p => p.Card.Equals(sugg.RoomCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == true/*p.Status == EPlayersCardInfoStatus.Yes*/)).Count() == 0)
                            {

                                PlayerCardInfo[] c1 = _playerCardInfoList.Where(p => p.Card.Equals(sugg.SuspectCard)
                                    //&& !p.Player.Equals(sugg.ConfirmPlayer)
                                    && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).ToArray();
                                if (_suspectCardSolution != null && _suspectCardSolution.Equals(sugg.SuspectCard) || c1.Length == 1 && !sugg.MovePlayer.Equals(c1[0].Player))
                                    sugg.SuspectCard = null;

                                PlayerCardInfo[] c2 = _playerCardInfoList.Where(p => p.Card.Equals(sugg.WeaponCard)
                                    //&& !p.Player.Equals(sugg.ConfirmPlayer)
                                    && p.PlayerHasCard == true /* p.Status == EPlayersCardInfoStatus.Yes */).ToArray();
                                if (_weaponCardSolution != null && _weaponCardSolution.Equals(sugg.WeaponCard) || c2.Length == 1 && !sugg.MovePlayer.Equals(c2[0].Player))
                                    sugg.WeaponCard = null;

                                PlayerCardInfo[] c3 = _playerCardInfoList.Where(p => p.Card.Equals(sugg.RoomCard)
                                    //&& !p.Player.Equals(sugg.ConfirmPlayer)
                                    && p.PlayerHasCard == true /*p.Status == EPlayersCardInfoStatus.Yes*/).ToArray();
                                if (_roomCardSolution != null && _roomCardSolution.Equals(sugg.RoomCard) || c3.Length == 1 && !sugg.MovePlayer.Equals(c3[0].Player))
                                    sugg.RoomCard = null;

                                if (sugg.SuspectCard != null && sugg.WeaponCard == null && sugg.RoomCard == null && !GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.SuspectCard).PlayerHasCard.HasValue /*GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.SuspectCard).Status != EPlayersCardInfoStatus.Yes && GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.SuspectCard).Status != EPlayersCardInfoStatus.No*/)
                                    SetPlayersCardInfo(sugg.ConfirmPlayer, sugg.SuspectCard, true /* EPlayersCardInfoStatus.Yes*/, EPlayerCardInfoStatusReason.MustHaveThatCard_BySystemOfEliminationUsingOthersSuggestions, i + 1);

                                if (sugg.SuspectCard == null && sugg.WeaponCard != null && sugg.RoomCard == null && !GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.WeaponCard).PlayerHasCard.HasValue /* Status != EPlayersCardInfoStatus.Yes && GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.WeaponCard).Status != EPlayersCardInfoStatus.No*/)
                                    SetPlayersCardInfo(sugg.ConfirmPlayer, sugg.WeaponCard, true /* EPlayersCardInfoStatus.Yes */, EPlayerCardInfoStatusReason.MustHaveThatCard_BySystemOfEliminationUsingOthersSuggestions, i + 1);

                                if (sugg.SuspectCard == null && sugg.WeaponCard == null && sugg.RoomCard != null && !GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.RoomCard).PlayerHasCard.HasValue /*Status != EPlayersCardInfoStatus.Yes && GetPlayersCardInfo(sugg.ConfirmPlayer, sugg.RoomCard).Status != EPlayersCardInfoStatus.No*/)
                                    SetPlayersCardInfo(sugg.ConfirmPlayer, sugg.RoomCard, true /*EPlayersCardInfoStatus.Yes*/, EPlayerCardInfoStatusReason.MustHaveThatCard_BySystemOfEliminationUsingOthersSuggestions, i + 1);
                            }


                            if (_playerCardInfoList.Where(p => p.Card.Equals(sugg.SuspectCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == false).Union(
                                _playerCardInfoList.Where(p => p.Card.Equals(sugg.WeaponCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == false)).Union(
                                _playerCardInfoList.Where(p => p.Card.Equals(sugg.RoomCard)
                                && p.Player.Equals(sugg.ConfirmPlayer)
                                && p.PlayerHasCard == false)).Count() == 2)
                            {
                                var pci = _playerCardInfoList.Where(p => (p.Card.Equals(sugg.SuspectCard) || p.Card.Equals(sugg.WeaponCard) || p.Card.Equals(sugg.RoomCard))
                                    && p.Player.Equals(sugg.ConfirmPlayer)
                                    && !p.PlayerHasCard.HasValue).SingleOrDefault();
                                
                                if (pci != null)
                                {
                                    pci.PlayerHasCard = true;
                                    pci.Reason = EPlayerCardInfoStatusReason.MustHaveThatCard_DoesNotHaveOtherTwoCardsOfSugg;
                                    pci.Suggestion = i + 1;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static GameLog[] GetGameLog()
        {
            return _gameLogList.ToArray();
        }


        public static bool Save()
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Detective Cluedo Files (*.dcf)|*.dcf";
            sfd.RestoreDirectory = true;

            try
            {

                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < Players.Length; i++)
                    {
                        if (i > 0)
                            sb.Append(";");
                        sb.Append(Players[i].Name);
                    }
                    sb.AppendLine("");

                    //
                    sb.AppendLine(GetYourself().Name);

                    //
                    var myCards = _playerCardInfoList.Where(p => p.Reason == EPlayerCardInfoStatusReason.MyCard).ToArray();
                    for (int i = 0; i < myCards.Length; i++)
                    {
                        if (i > 0)
                            sb.Append(";");
                        sb.Append(myCards[i].Card.Name + "[" + myCards[i].Card.Type + "]");
                    }
                    sb.AppendLine("");

                    //
                    foreach (GameLog gl in _gameLogList)
                    {
                        sb.AppendLine(string.Format("{0};{1};{2};{3};{4};{5}", gl.MovePlayer.Name, gl.RoomCard.Name, gl.SuspectCard.Name, gl.WeaponCard.Name, (gl.DisapprovePlayer != null) ? gl.DisapprovePlayer.Name : "", (gl.ShownCard != null) ? gl.ShownCard.Name + "[" + gl.ShownCard.Type.ToString() + "]" : ""));
                    }

                    File.WriteAllLines(sfd.FileName, Regex.Split(sb.ToString(), Environment.NewLine));
                }
                return true;
            }
            catch { return false; }
        }

        public static bool Open()
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Detective Cluedo Files (*.dcf)|*.dcf";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                CluedoGame.StartNewGame();


                List<GameLog> gl = new List<GameLog>();

                var lines = File.ReadAllLines(ofd.FileName);

                string[] players = lines[0].Split(';');
                CluedoGame.CreatePlayers(players);

                bool b = CluedoGame.SetYourself(lines[1]);

                var cardsString = lines[2].Split(';');
                foreach (var s in cardsString)
                {
                    string name = s.Substring(0, s.IndexOf("["));
                    string type = s.Substring(s.IndexOf("[") + 1, s.IndexOf("]") - s.IndexOf("[") - 1);

                    Card card = new Card() { Name = name, Type = (ECardType)Enum.Parse(typeof(ECardType), type) };
                    CluedoGame.SetPlayersCardInfo(CluedoGame.GetYourself(), card, true, EPlayerCardInfoStatusReason.MyCard);
                }

                for (int i = 3; i < lines.Length; i++)
                {
                    if (!string.IsNullOrEmpty(lines[i]) && !lines[i].StartsWith("--"))
                    {
                        Console.WriteLine("Line " + i.ToString());

                        var line = lines[i].Split(';');
                        string cardName = "";
                        ECardType cardType = ECardType.Suspect;

                        if (!string.IsNullOrEmpty(line[5]))
                        {
                            cardName = line[5].Substring(0, line[5].IndexOf("["));
                            cardType = (ECardType)Enum.Parse(typeof(ECardType), line[5].Substring(line[5].IndexOf("[") + 1, line[5].IndexOf("]") - line[5].IndexOf("[") - 1));
                        }

                        gl.Add(new GameLog(
                            CluedoGame.GetPlayerByName(line[0]),
                            CluedoGame.GetPlayerByName(line[4]),
                            CluedoGame.GetCardByNameAndType(line[2], ECardType.Suspect),
                            CluedoGame.GetCardByNameAndType(line[3], ECardType.Weapon),
                            CluedoGame.GetCardByNameAndType(line[1], ECardType.Room),
                            (!string.IsNullOrEmpty(line[5]) ? CluedoGame.GetCardByNameAndType(cardName, cardType) : null)
                        ));
                    }
                }
                _gameLogList.AddRange(gl);

                return true;
            }


            return false;


        }
    }
}
